<?php
/**
 * Cube PHP Framework
 * 
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * @author Dillen / Steffen
 */

namespace Library\Mvc;

/**
 * @class Library.Mvc.Router
 * 
 * Router class description
 */
class Router
{
	/**
	 * Application instance
	 * 
	 * @property {Array} config
	 * @private
	 */
	private $_config;
	
	/**
	 * Rewrite rules
	 * 
	 * @property {Array} _rules
	 * @private
	 */
	private $_rules = array();
	
	/**
	 * Controller instance
	 * 
	 * @property {Library.Mvc.Controller} _controller
	 */
	private $_controller;
    
	private $_request;
	
	/**
	 * Constructor
	 * 
	 * @method __construct
	 * @param {Library.Mvc.Request} $request
	 * @param {String} $module
	 */
	public function __construct(Request $request)
	{
		$this->_config = \Library\Platform::getConfig();
		$this->_request = $request;
	}
	
	/**
	 * Add router dispatch rule 
	 *
	 * @method addRule
	 * @param {String} $from
	 * @param {String} $to
	 */
	public function addRule($from, $to)
	{
		// TODO
	}
    
    public function preDispatch()
    {
        //Parse the routing settings
        $this->_parseRouting();
        
        //Set request default action and controller
        $this->_request->controller = $this->_request->controller == null ? $this->_config['application']['default_controller'] : $this->_request->controller;
        $this->_request->action = $this->_request->action == null ? $this->_config['application']['default_action'] : $this->_request->action;
    
        try
        {
            $class = $this->_config['application']['namespace'] . '\\Controllers\\' . $this->_request->controller;
            $this->_controller = new $class;
        }
        catch(\Library\Autoloader\Exception\ClassNotFoundException $exception)
        {
            throw new \Exception('Controller ' . $this->request->controller . ' does not exist.');
        }
    }
	
	/**
	 * Dispatch the router and call the actual controller action
	 * 
	 * @method dispatch
	 */
	public function dispatch($bootstrap = null)
	{
        //Unsafe controller creating
        if ($this->_controller == null)
        {
            $class = $this->config['application']['namespace'] . '\\Controllers\\' . $this->_request->controller;
            $this->_controller = new $class;
        }
        
        //Call controller 'constructor'
        $this->_controller->__init();
        
        //Check if the action exists
        if (!method_exists($this->_controller, $this->_request->action . 'Action'))
        {
            throw new \Exception('Action ' . $this->_request->action . ' does not exist.');
        }
        
        //Set instances
        $this->_controller->request = $this->_request;
        
        $layout = $this->_controller->createResponse();
        
        if ($bootstrap != null)
        {
            $bootstrap->callEvent('layoutPrerender', $layout);
        }

        //Call and parse controller response
        $result = \Library\Platform::call($this->_controller, $this->_request->action . 'Action', $this->_request->parameters);
        
        if ($result !== false)
        {
            $this->_controller->parseResponse();
        }
        
        return $result;
	}
	
	/**
	 * Parse routing
	 * 
	 * Checks in settings.ini for the routing section and parses all the routing configuration.
	 * If no routing is configured, the request won't change.
	 * 
	 * @method _parseRouting
	 * @private
	 * @return string|false Request uri string
	 */
	private function _parseRouting()
	{
		// Get the application instance of this module
		$routing = $this->_config['routing'];
		
		foreach ( $routing as $key => $value )
        {			
            // Convert wildcards
            $key = str_replace(':any', '(.+)', $key);
            $key = str_replace(':all', '(.*)', $key);
            $key = str_replace(':text', '([a-zA-Z0-9\-\_]*)', $key);
            $key = str_replace(':empty', '', $key);
            
            if ( preg_match('#^' . $key . '$#', $this->_request->requestUri) )
            {
                $value = rtrim($value);
                
                // Only replace back-references when there is one
                if ( strpos($value, '$') )
                {
                    $value = preg_replace('#^'.$key.'$#', $value, $this->_request->requestUri);
                }
                
             	$this->_request = new \Library\Mvc\Request($value);
            }
        }
		
		return false;
	}
}